// Copyright 2011-2012, Vanya Davidenko.
// Используемая кодировка: UTF-8.

#ifndef LIBV_TESTS_INTEGER_TESTS_H_
#define LIBV_TESTS_INTEGER_TESTS_H_

#include <gtest/gtest.h>
#include <libv/typed_integer.h>



namespace libv {
namespace tests {

class IntegerTests : public ::testing::Test {
  public:
    virtual void SetUp() {}
    virtual void TearDown() {}

  protected:
    class IntegerType : public TypedInteger<IntegerType, int> {
      private:
        typedef libv::TypedInteger<IntegerType, int> base_type;

      public:
        typedef base_type::Int Int;
        IntegerType() {}
        explicit IntegerType(const Int& value) : base_type(value) {}
    };

    IntegerType value;
};

TEST_F(IntegerTests, DefaultConstuctor) {
    ASSERT_TRUE(value == IntegerType(0));
}

TEST_F(IntegerTests, Constructor) {
    IntegerType test_value(10);
    EXPECT_EQ(10, test_value.value());
}

TEST_F(IntegerTests, AssignAndCopy) {
    value.value() = 10;

    IntegerType second_value(value);
    EXPECT_EQ(value, second_value);

    IntegerType third_value;
    third_value = value;
    EXPECT_EQ(value, third_value);
}

TEST_F(IntegerTests, ComparisonOperations) {
    const int big_value = 121;
    const int small_value = 100;

    EXPECT_TRUE(IntegerType(big_value) > IntegerType(small_value));
    EXPECT_FALSE(IntegerType(big_value) > IntegerType(big_value));

    EXPECT_TRUE(IntegerType(big_value) >= IntegerType(small_value));
    EXPECT_TRUE(IntegerType(big_value) >= IntegerType(big_value));

    EXPECT_TRUE(IntegerType(small_value) < IntegerType(big_value));
    EXPECT_FALSE(IntegerType(small_value) < IntegerType(small_value));

    EXPECT_TRUE(IntegerType(small_value) < IntegerType(big_value));
    EXPECT_TRUE(IntegerType(small_value) <= IntegerType(small_value));

    EXPECT_TRUE(IntegerType(big_value) != IntegerType(small_value));
    EXPECT_FALSE(IntegerType(big_value) != IntegerType(big_value));

    EXPECT_TRUE(IntegerType(big_value) == IntegerType(big_value));
    EXPECT_FALSE(IntegerType(small_value) == IntegerType(big_value));
}

TEST_F(IntegerTests, AssignOperations) {
    value += IntegerType(1);
    ASSERT_TRUE(value == IntegerType(1));

    value -= IntegerType(5);
    ASSERT_TRUE(value == IntegerType(-4));

    value *= IntegerType(-2);
    ASSERT_TRUE(value == IntegerType(8));

    value /= IntegerType(4);
    ASSERT_TRUE(value == IntegerType(2));

    value ^= value;
    ASSERT_TRUE(value == IntegerType(0));

    value |= IntegerType(13);
    ASSERT_TRUE(value == IntegerType(13));

    value &= IntegerType(7);
    ASSERT_TRUE(value == IntegerType(5));
}

TEST_F(IntegerTests, BinaryOperations) {
    // Так как все операции реализованы через операторы с присваиванием,
    // проверим только сложение.
    const IntegerType default_value = IntegerType(10);

    value = default_value;
    IntegerType second_value = value + IntegerType(15);
    EXPECT_EQ(IntegerType(25), second_value);
    EXPECT_EQ(default_value, value);
}

TEST_F(IntegerTests, UnaryOperations) {
    const int default_value = 123;

    value = IntegerType(default_value);
    EXPECT_EQ(IntegerType(-default_value), -value);
    EXPECT_EQ(IntegerType(default_value), +value);
    EXPECT_EQ(IntegerType(~default_value), ~value);

    EXPECT_EQ(false, !value);
}

TEST_F(IntegerTests, PreIncDec) {
    int default_value = 93;

    value = IntegerType(default_value);

    EXPECT_EQ(IntegerType(default_value + 1), ++value);
    EXPECT_EQ(IntegerType(default_value + 1), value);

    EXPECT_EQ(IntegerType(default_value), --value);
    EXPECT_EQ(IntegerType(default_value), value);
}

TEST_F(IntegerTests, PostIncDec) {
    int default_value = 27;

    value = IntegerType(default_value);

    EXPECT_EQ(IntegerType(default_value), value++);
    EXPECT_EQ(IntegerType(default_value + 1), value);

    EXPECT_EQ(IntegerType(default_value + 1), value--);
    EXPECT_EQ(IntegerType(default_value), value);
}
}  // testring
}  // libv

#endif  // LIBV_TESTS_INTEGER_TESTS_H_